package com.crl.rcdp.sys.service;

import com.cars.util.auth.AuthDTO;
import com.cars.util.global.AuthTypeEnum;
import com.cars.util.global.GlobalConst;
import com.cars.util.json.JsonResult;
import com.cars.util.json.JsonResultUtil;
import com.cars.util.jwt.JwtResult;
import com.cars.util.jwt.JwtUtil;
import com.crl.rcdp.sys.dao.SysLoginLogDao;
import com.crl.rcdp.sys.dao.SysResourceDao;
import com.crl.rcdp.sys.dao.SysUserLoginDao;
import com.crl.rcdp.sys.dao.SysUserRoleDao;
import com.crl.rcdp.sys.dto.SysUserLoginDTO;
import com.crl.rcdp.sys.model.SysLoginLog;
import com.crl.rcdp.sys.model.SysUserLogin;
import com.crl.rcdp.sys.model.SysUserRole;
import com.crl.redis.RedisKey;
import com.crl.redis.RedisUtil;
import org.apache.commons.collections4.map.HashedMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: 孔垂云
 * @version: 1.0
 * @date: 2020/7/5 15:51
 */
@Service
public class SysUserLoginService {
    @Autowired
    private SysUserLoginDao sysUserloginDao;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysLoginLogDao sysLoginLogDao;
    @Autowired
    private SysResourceDao sysResourceDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;

    /**
     * 用户登录
     *
     * @param sysUserLoginDTO
     * @return
     */
    public JsonResult checkLogin(SysUserLoginDTO sysUserLoginDTO) {
        this.addSysLoginLog(sysUserLoginDTO);//加入登录日志

        SysUserLogin sysUserLogin = sysUserloginDao.getByUsername(sysUserLoginDTO.getUsername());
//        String password = new String(Base64Utils.decode(sysUserLoginDTO.getPassword().getBytes()));
        sysUserLoginDTO.setPassword(sysUserLoginDTO.getPassword());
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(10);
        if (sysUserLogin == null) {
            return JsonResultUtil.error("账号密码错误");//账号密码错误
        } else if (!bCryptPasswordEncoder.matches(sysUserLoginDTO.getPassword(), sysUserLogin.getPassword())) {
            return JsonResultUtil.error("账号密码错误");//账号密码错误;
        } else {
            Map<String, String> map = new HashedMap<>();
            String accessToken = JwtUtil.generateJWT(GlobalConst.TOKEN_EXPIRED, sysUserLoginDTO.getUsername(), sysUserLogin.getUserId(), 1);
//            String refreshToken = JwtUtil.generateJWT(GlobalConst.REFRESH_TOKEN_EXPIRED, sysUserLoginDTO.getUsername(), sysUserLogin.getUserId(), 1);
            map.put("accessToken", accessToken);
//            map.put("refreshToken", refreshToken);
            //设值redis权限
            this.getAuthDTO(accessToken, sysUserLogin.getUserId());
            this.updateLastLoginTime(sysUserLoginDTO.getUsername());
            return JsonResultUtil.ok(map);
        }
    }

    /**
     * 注销
     *
     * @param accessToken
     */
    public void logout(String accessToken) {
        JwtResult jwtResult = JwtUtil.parseJWT(accessToken);
        if (jwtResult.isValid()) {
            redisUtil.del(RedisKey.AUTH_PASSWORD_KEY + JwtUtil.getJWTOwner(accessToken));
        }
    }

    /**
     * 根据refresh_token刷新access_token
     *
     * @param refreshToken refresh_token
     * @return 新的token
     */
    public JsonResult getTokenByRefresh(String refreshToken) {
        JsonResult jsonResult;
        JwtResult jwtResult = JwtUtil.parseJWT(refreshToken);
        boolean isValid = jwtResult.isValid();
        // 校验refreshtoken是否有效
        if (isValid) {
            String username = jwtResult.getOwner();
            int userId = JwtUtil.getUserId(refreshToken);
            //修改最后登录时间
            String accessToken = JwtUtil.generateJWT(GlobalConst.TOKEN_EXPIRED, username, userId, AuthTypeEnum.PASSWORD.getValue());
            Map<String, String> map = new HashMap<>(2);
            map.put("accessToken", accessToken);
            map.put("refreshToken", refreshToken);
            jsonResult = JsonResultUtil.ok(map);
//            authRedisService.saveUserAccessToken(username, JwtUtil.parseJWT(token).getToken());
//            redisUtil.del(RedisKey.AUTH_PASSWORD_KEY + accessToken);
            //把历史的清理掉 TODO，可以把refreshtoken的value当做accesstoken
            this.getAuthDTO(accessToken, userId);// TODO userId设置值
        } else {
            jsonResult = JsonResultUtil.error("无效的REFRESH_TOKEN!");
        }
        return jsonResult;
    }

    /**
     * 根据accessToken获取authDTO
     *
     * @param accessToken
     * @return
     */
    private AuthDTO getAuthDTO(String accessToken, int userId) {
        String username = JwtUtil.getJWTOwner(accessToken);
        AuthDTO authDTO = redisUtil.get(RedisKey.AUTH_PASSWORD_KEY + username, AuthDTO.class);
        if (authDTO == null) {
            authDTO = new AuthDTO();
            authDTO.setToken(accessToken);
            //获取appid
            authDTO.setOwner(username);
            authDTO.setAuthType(AuthTypeEnum.PASSWORD.getValue());//授权方式
            //设置用户对应的角色
            List<SysUserRole> listByUserId = sysUserRoleDao.listByUserId(userId);
            List<Integer> listRoles = new ArrayList<>();
            for (SysUserRole sysUserRole : listByUserId) {
                listRoles.add(sysUserRole.getRoleId());
            }
            authDTO.setListRoles(listRoles);//用具具备的角色列表
            redisUtil.set(RedisKey.AUTH_PASSWORD_KEY + username, authDTO);
        }
        return authDTO;
    }

    /**
     * 加入登录日志，异步操作
     *
     * @param sysUserLoginDTO
     */
    @Async
    public void addSysLoginLog(SysUserLoginDTO sysUserLoginDTO) {
        SysLoginLog sysLoginLog = new SysLoginLog();      //加入登录日志表
        sysLoginLog.setLoginIp(sysUserLoginDTO.getClientIp());
        sysLoginLog.setUsername(sysUserLoginDTO.getUsername());
        sysLoginLog.setAuthType(AuthTypeEnum.PASSWORD.getValue());//授权方式
        sysLoginLogDao.add(sysLoginLog);//异步处理
    }

    /**
     * 加入登录日志，异步操作
     *
     * @param username
     */
    @Async
    public void updateLastLoginTime(String username) {
        sysUserloginDao.updateLastLoginTime(username);//异步处理
    }


}
